Completed
Push — stable8.2 ( 09e830...ae9bfd )
by Olivier
12:09
created

Gallery.move   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 5
nc 4
nop 1
dl 0
loc 25
rs 8.439
c 2
b 0
f 0
1
/* global Album, GalleryImage */
2
(function ($, OC, t) {
3
	"use strict";
4
	var Gallery = {
5
		currentAlbum: null,
6
		currentEtag: null,
7
		config: {},
8
		/** Map of the whole gallery, built as we navigate through folders */
9
		albumMap: {},
10
		/** Used to pick an image based on the URL */
11
		imageMap: {},
12
		appName: 'galleryplus',
13
		token: undefined,
14
		activeSlideShow: null,
15
		buttonsWidth: 650,
16
		browserToolbarHeight: 150,
17
18
		/**
19
		 * Refreshes the view and starts the slideshow if required
20
		 *
21
		 * @param {string} path
22
		 * @param {string} albumPath
23
		 */
24
		refresh: function (path, albumPath) {
25
			if (Gallery.currentAlbum !== albumPath) {
26
				Gallery.view.init(albumPath, null);
27
			}
28
29
			// If the path is mapped, that means that it's an albumPath
30
			if (Gallery.albumMap[path]) {
31
				if (Gallery.activeSlideShow) {
32
					Gallery.activeSlideShow.stop();
33
				}
34
			} else if (Gallery.imageMap[path] && Gallery.activeSlideShow.active === false) {
35
				Gallery.view.startSlideshow(path, albumPath);
36
			}
37
		},
38
39
		/**
40
		 * Retrieves information about all the images and albums located in the current folder
41
		 *
42
		 * @param {string} currentLocation
43
		 *
44
		 * @returns {*}
45
		 */
46
		getFiles: function (currentLocation) {
47
			// Cache the sorting order of the current album before loading new files
48
			if (!$.isEmptyObject(Gallery.albumMap)) {
49
				Gallery.albumMap[Gallery.currentAlbum].sorting = Gallery.config.albumSorting;
50
			}
51
			// Checks if we've visited this location before ands saves the etag to use for
52
			// comparison later
53
			var albumEtag;
54
			var albumCache = Gallery.albumMap[decodeURIComponent(currentLocation)];
55
			if (!$.isEmptyObject(albumCache)) {
56
				albumEtag = albumCache.etag;
57
			}
58
59
			// Sends the request to the server
60
			var params = {
61
				location: currentLocation,
62
				mediatypes: Gallery.config.getMediaTypes(),
63
				features: Gallery.config.getFeatures(),
64
				etag: albumEtag
0 ignored issues
show
Bug introduced by
The variable albumEtag does not seem to be initialized in case !$.isEmptyObject(albumCache) on line 55 is false. Are you sure this can never be the case?
Loading history...
65
			};
66
			// Only use the folder as a GET parameter and not as part of the URL
67
			var url = Gallery.utility.buildGalleryUrl('files', '/list', params);
68
			return $.getJSON(url).then(
69
				function (/**@type{{
70
					* files:Array,
71
					* albums:Array,
72
					* albumconfig:Object,
73
					* albumpath:String,
74
					* updated:Boolean}}*/
75
						  data) {
76
					var albumpath = data.albumpath;
77
					var updated = data.updated;
78
					// FIXME albumConfig should be cached as well
79
					/**@type {{design,information,sorting,error: string}}*/
80
					var albumConfig = data.albumconfig;
81
					//Gallery.config.setAlbumPermissions(currentAlbum);
82
					Gallery.config.setAlbumConfig(albumConfig, albumpath);
83
					// Both the folder and the etag have to match
84
					if ((decodeURIComponent(currentLocation) === albumpath) &&
85
						(updated === false)) {
86
						Gallery.imageMap = albumCache.imageMap;
87
					} else {
88
						Gallery._mapFiles(data);
89
					}
90
91
					// Restore the previous sorting order for this album
92
					if (!$.isEmptyObject(Gallery.albumMap[albumpath].sorting)) {
93
						Gallery.config.updateAlbumSorting(
94
							Gallery.albumMap[albumpath].sorting);
95
					}
96
97
				}, function (xhr) {
98
					var result = xhr.responseJSON;
99
					var albumPath = decodeURIComponent(currentLocation);
100
					var message;
101
					if (result === null) {
102
						message = t('gallery', 'There was a problem reading files from this album');
103
					} else {
104
						message = result.message;
105
					}
106
					Gallery.view.init(albumPath, message);
107
					Gallery._mapStructure(albumPath);
108
				});
109
		},
110
111
		/**
112
		 * Sorts albums and images based on user preferences
113
		 */
114
		sorter: function () {
115
			var sortType = 'name';
116
			var sortOrder = 'asc';
117
			var albumSortType = 'name';
118
			var albumSortOrder = 'asc';
119
			if (this.id === 'sort-date-button') {
120
				sortType = 'date';
121
122
			}
123
			var currentSort = Gallery.config.albumSorting;
124
			if (currentSort.type === sortType && currentSort.order === sortOrder) {
125
				sortOrder = 'des';
126
			}
127
128
			// Update the controls
129
			Gallery.view.sortControlsSetup(sortType, sortOrder);
130
131
			// We can't currently sort by album creation time
132
			if (sortType === 'name') {
133
				albumSortOrder = sortOrder;
134
			}
135
136
			// FIXME Rendering is still happening while we're sorting...
137
138
			// Clear before sorting
139
			Gallery.view.clear();
140
141
			// Sort the images
142
			Gallery.albumMap[Gallery.currentAlbum].images.sort(Gallery.utility.sortBy(sortType,
143
				sortOrder));
144
			Gallery.albumMap[Gallery.currentAlbum].subAlbums.sort(
145
				Gallery.utility.sortBy(albumSortType,
146
					albumSortOrder));
147
148
			// Save the new settings
149
			var sortConfig = {
150
				type: sortType,
151
				order: sortOrder,
152
				albumOrder: albumSortOrder
153
			};
154
			Gallery.config.updateAlbumSorting(sortConfig);
155
156
			// Refresh the view
157
			Gallery.view.viewAlbum(Gallery.currentAlbum);
158
		},
159
160
		/**
161
		 * Switches to the Files view
162
		 *
163
		 * @param event
164
		 */
165
		switchToFilesView: function (event) {
166
			event.stopPropagation();
167
168
			var subUrl = '';
169
			var params = {path: '/' + Gallery.currentAlbum};
170
			if (Gallery.token) {
171
				params.token = Gallery.token;
172
				subUrl = 's/{token}?path={path}';
173
			} else {
174
				subUrl = 'apps/files?dir={path}';
175
			}
176
177
			var button = $('#filelist-button');
178
			button.children('#button-loading').addClass('loading');
179
			OC.redirect(OC.generateUrl(subUrl, params));
180
		},
181
182
		/**
183
		 * Populates the share dialog with the needed information
184
		 *
185
		 * @param event
186
		 */
187
		share: function (event) {
188
			// Clicking on share button does not trigger automatic slide-up
189
			$('.album-info-container').slideUp();
190
191
			if (!OC.Share.droppedDown) {
192
				event.preventDefault();
193
				event.stopPropagation();
194
195
				(function () {
196
					var target = OC.Share.showLink;
197
					OC.Share.showLink = function () {
198
						var r = target.apply(this, arguments);
199
						$('#linkText').val($('#linkText').val().replace('index.php/s/',
200
							'index.php/apps/' +
201
							Gallery.appName + '/s/'));
202
203
						return r;
204
					};
205
				})();
206
207
				var currentAlbum = Gallery.albumMap[Gallery.currentAlbum];
208
				$('a.share').data('item', currentAlbum.fileid)
209
					.data('link', true)
210
					.data('possible-permissions', currentAlbum.permissions)
211
					.click();
212
				if (!$('#linkCheckbox').is(':checked')) {
213
					$('#linkText').hide();
214
				}
215
			}
216
		},
217
218
		/**
219
		 * Sends an archive of the current folder to the browser
220
		 *
221
		 * @param event
222
		 */
223
		download: function (event) {
224
			event.preventDefault();
225
226
			var path = $('#content').data('albumname');
227
			var files = Gallery.currentAlbum;
228
			var downloadUrl = Gallery.utility.buildFilesUrl(path, files);
229
230
			OC.redirect(downloadUrl);
231
		},
232
233
		/**
234
		 * Shows an information box to the user
235
		 *
236
		 * @param event
237
		 */
238
		showInfo: function (event) {
239
			event.stopPropagation();
240
			Gallery.infoBox.showInfo();
241
		},
242
243
		/**
244
		 * Lets the user add the shared files to his ownCloud
245
		 */
246
		showSaveForm: function () {
247
			$(this).hide();
248
			$('.save-form').css('display', 'inline');
249
			$('#remote_address').focus();
250
		},
251
252
		/**
253
		 * Sends the shared files to the viewer's ownCloud
254
		 *
255
		 * @param event
256
		 */
257
		saveForm: function (event) {
258
			event.preventDefault();
259
260
			var saveElement = $('#save');
261
			var remote = $(this).find('input[type="text"]').val();
262
			var owner = saveElement.data('owner');
263
			var name = saveElement.data('name');
264
			var isProtected = saveElement.data('protected');
265
			Gallery._saveToOwnCloud(remote, Gallery.token, owner, name, isProtected);
266
		},
267
268
		/**
269
		 * Creates a new slideshow using the images found in the current folder
270
		 *
271
		 * @param {Array} images
272
		 * @param {string} startImage
273
		 * @param {boolean} autoPlay
274
		 *
275
		 * @returns {boolean}
276
		 */
277
		slideShow: function (images, startImage, autoPlay) {
278
			if (startImage === undefined) {
279
				OC.Notification.showTemporary(t('gallery',
280
					'Aborting preview. Could not find the file'));
281
				return false;
282
			}
283
			var start = images.indexOf(startImage);
284
			images = images.filter(function (image, index) {
285
				// If the slideshow is loaded before we get a thumbnail, we have to accept all
286
				// images
287
				if (!image.thumbnail) {
288
					return image;
289
				} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
290
					if (image.thumbnail.valid) {
291
						return image;
292
					} else if (index < images.indexOf(startImage)) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if index < images.indexOf(startImage) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
293
						start--;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
294
					}
295
				}
296
			}).map(function (image) {
297
				var name = OC.basename(image.path);
298
				var previewUrl = Gallery.utility.getPreviewUrl(image.fileId, image.etag);
299
				var params = {
300
					c: image.etag,
301
					requesttoken: oc_requesttoken
0 ignored issues
show
Bug introduced by
The variable oc_requesttoken seems to be never declared. If this is a global, consider adding a /** global: oc_requesttoken */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
302
				};
303
				var downloadUrl = Gallery.utility.buildGalleryUrl('files',
304
					'/download/' + image.fileId,
305
					params);
306
307
				return {
308
					name: name,
309
					path: image.path,
310
					file: image.fileId,
311
					mimeType: image.mimeType,
312
					url: previewUrl,
313
					downloadUrl: downloadUrl
314
				};
315
			});
316
			Gallery.activeSlideShow.setImages(images, autoPlay);
317
			Gallery.activeSlideShow.onStop = function () {
318
				$('#content').show();
319
				Gallery.view.removeLoading();
320
				if (Gallery.currentAlbum !== '') {
321
					// Only modern browsers can manipulate history
322
					if (history && history.replaceState) {
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable history is declared in the current environment, consider using typeof history === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
323
						history.replaceState('', '',
324
							'#' + encodeURIComponent(Gallery.currentAlbum));
325
					} else {
326
						location.hash = '#' + encodeURIComponent(Gallery.currentAlbum);
327
					}
328
				} else {
329
					// Only modern browsers can manipulate history
330
					if (history && history.replaceState) {
331
						history.replaceState('', '', '#');
332
					} else {
333
						location.hash = '#';
334
					}
335
				}
336
			};
337
			Gallery.activeSlideShow.show(start);
338
			if (!_.isUndefined(Gallery.Share)) {
339
				Gallery.Share.hideDropDown();
340
			}
341
			$('.album-info-container').slideUp();
342
			// Resets the last focused element
343
			document.activeElement.blur();
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
344
		},
345
346
		/**
347
		 * Moves files and albums to a new location
348
		 *
349
		 * @param {jQuery} $item
350
		 * @param {string} fileName
351
		 * @param {string} filePath
352
		 * @param {jQuery} $target
353
		 * @param {string} targetPath
354
		 */
355
		move: function ($item, fileName, filePath, $target, targetPath) {
356
			var self = this;
357
			var dir = Gallery.currentAlbum;
358
359
			if (targetPath.charAt(targetPath.length - 1) !== '/') {
360
				// make sure we move the files into the target dir,
361
				// not overwrite it
362
				targetPath = targetPath + '/';
363
			}
364
			$.post(OC.generateUrl('apps/files/ajax/move.php'),
365
				{
366
					dir: Gallery.currentAlbum,
367
					file: fileName,
368
					target: targetPath
369
				},
370
				function (result) {
371
					if (result) {
372
						if (result.status === 'success') {
373
							self._removeElement(dir, filePath, $item);
374
						} else {
375
							if (result.status === 'error' && result.data.message) {
376
								OC.Notification.showTemporary(result.data.message);
377
							}
378
							else {
379
								OC.Notification.showTemporary(
380
									t('gallery', 'Could not move "{file}", target exists',
381
										{file: fileName})
382
								);
383
							}
384
							$item.fadeTo("normal", 1);
385
							$target.children('.album-loader').hide();
386
						}
387
					} else {
388
						OC.dialogs.alert(
389
							t('gallery', 'Could not move "{file}", target exists', {file: fileName})
390
						);
391
						$item.fadeTo("normal", 1);
392
						$target.children('.album-loader').hide();
393
					}
394
				}
395
			);
396
		},
397
398
		/**
399
		 * Builds the album's model
400
		 *
401
		 * @param {{
402
		 * 	files:Array,
403
		 * 	albums:Array,
404
		 * 	albumconfig:Object,
405
		 * 	albumpath:String,
406
		 *	updated:Boolean
407
		 * 	}} data
408
		 * @private
409
		 */
410
		_mapFiles: function (data) {
411
			Gallery.imageMap = {};
412
			var image = null;
0 ignored issues
show
Unused Code introduced by
The assignment to image seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
413
			var path = null;
414
			var fileId = null;
0 ignored issues
show
Unused Code introduced by
The assignment to fileId seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
415
			var mimeType = null;
0 ignored issues
show
Unused Code introduced by
The assignment to mimeType seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
416
			var mTime = null;
0 ignored issues
show
Unused Code introduced by
The assignment to mTime seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
417
			var etag = null;
418
			var size = null;
419
			var sharedWithUser = null;
0 ignored issues
show
Unused Code introduced by
The assignment to sharedWithUser seems to be never used. If you intend to free memory here, this is not necessary since the variable leaves the scope anyway.
Loading history...
420
			var currentLocation = data.albumpath;
421
			// This adds a new node to the map for each parent album
422
			Gallery._mapStructure(currentLocation);
423
			var files = data.files;
424
			if (files.length > 0) {
425
				var subAlbumCache = {};
426
				var albumCache = Gallery.albumMap[currentLocation]
427
					= new Album(
428
					currentLocation,
429
					[],
430
					[],
431
					OC.basename(currentLocation),
432
					data.albums[currentLocation].nodeid,
433
					data.albums[currentLocation].mtime,
434
					data.albums[currentLocation].etag,
435
					data.albums[currentLocation].size,
436
					data.albums[currentLocation].sharedwithuser,
437
					data.albums[currentLocation].freespace,
438
					data.albums[currentLocation].permissions
439
				);
440
				for (var i = 0; i < files.length; i++) {
441
					path = files[i].path;
442
					fileId = files[i].nodeid;
443
					mimeType = files[i].mimetype;
444
					mTime = files[i].mtime;
445
					etag = files[i].etag;
446
					size = files[i].size;
447
					sharedWithUser = files[i].sharedwithuser;
448
449
					image =
450
						new GalleryImage(
451
							path, path, fileId, mimeType, mTime, etag, size, sharedWithUser
452
						);
453
454
					// Determines the folder name for the image
455
					var dir = OC.dirname(path);
456
					if (dir === path) {
457
						dir = '';
458
					}
459
					if (dir === currentLocation) {
460
						// The image belongs to the current album, so we can add it directly
461
						albumCache.images.push(image);
462
					} else {
463
						// The image belongs to a sub-album, so we create a sub-album cache if it
464
						// doesn't exist and add images to it
465
						if (!subAlbumCache[dir]) {
466
							subAlbumCache[dir] = new Album(
467
								dir,
468
								[],
469
								[],
470
								OC.basename(dir),
471
								data.albums[dir].nodeid,
472
								data.albums[dir].mtime,
473
								data.albums[dir].etag,
474
								data.albums[dir].size,
475
								data.albums[dir].sharedwithuser,
476
								data.albums[currentLocation].freespace,
477
								data.albums[dir].permissions);
478
						}
479
						subAlbumCache[dir].images.push(image);
480
						// The sub-album also has to be added to the global map
481
						if (!Gallery.albumMap[dir]) {
482
							Gallery.albumMap[dir] = {};
483
						}
484
					}
485
					Gallery.imageMap[image.path] = image;
486
				}
487
				// Adds the sub-albums to the current album
488
				Gallery._mapAlbums(albumCache, subAlbumCache);
489
490
				// Caches the information which is not already cached
491
				albumCache.etag = data.albums[currentLocation].etag;
492
				albumCache.imageMap = Gallery.imageMap;
493
			}
494
		},
495
496
		/**
497
		 * Adds every album leading to the current folder to a global album map
498
		 *
499
		 * Per example, if you have Root/Folder1/Folder2/CurrentFolder then the map will contain:
500
		 *    * Root
501
		 *    * Folder1
502
		 *    * Folder2
503
		 *    * CurrentFolder
504
		 *
505
		 *  Every time a new location is loaded, the map is completed
506
		 *
507
		 *
508
		 * @param {string} path
509
		 *
510
		 * @returns {Album}
511
		 * @private
512
		 */
513
		_mapStructure: function (path) {
514
			if (!Gallery.albumMap[path]) {
515
				Gallery.albumMap[path] = {};
516
				// Builds relationships between albums
517
				if (path !== '') {
518
					var parent = OC.dirname(path);
519
					if (parent === path) {
520
						parent = '';
521
					}
522
					Gallery._mapStructure(parent);
523
				}
524
			}
525
			return Gallery.albumMap[path];
526
		},
527
528
		/**
529
		 * Adds the sub-albums to the current album
530
		 *
531
		 * @param {Album} albumCache
532
		 * @param {{Album}} subAlbumCache
533
		 * @private
534
		 */
535
		_mapAlbums: function (albumCache, subAlbumCache) {
536
			for (var j = 0, keys = Object.keys(subAlbumCache); j <
537
			keys.length; j++) {
538
				albumCache.subAlbums.push(subAlbumCache[keys[j]]);
539
			}
540
		},
541
542
		/**
543
		 * Saves the folder to a remote ownCloud installation
544
		 *
545
		 * Our location is the remote for the other server
546
		 *
547
		 * @param {string} remote
548
		 * @param {string}token
549
		 * @param {string}owner
550
		 * @param {string}name
551
		 * @param {boolean} isProtected
552
		 * @private
553
		 */
554
		_saveToOwnCloud: function (remote, token, owner, name, isProtected) {
555
			var location = window.location.protocol + '//' + window.location.host + OC.webroot;
556
			var isProtectedInt = (isProtected) ? 1 : 0;
557
			var url = remote + '/index.php/apps/files#' + 'remote=' + encodeURIComponent(location)
558
				+ "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) +
559
				"&name=" +
560
				encodeURIComponent(name) + "&protected=" + isProtectedInt;
561
562
			if (remote.indexOf('://') > 0) {
563
				OC.redirect(url);
564
			} else {
565
				// if no protocol is specified, we automatically detect it by testing https and
566
				// http
567
				// this check needs to happen on the server due to the Content Security Policy
568
				// directive
569
				$.get(OC.generateUrl('apps/files_sharing/testremote'),
570
					{remote: remote}).then(function (protocol) {
571
					if (protocol !== 'http' && protocol !== 'https') {
572
						OC.dialogs.alert(t('files_sharing',
573
							'No ownCloud installation (7 or higher) found at {remote}',
574
							{remote: remote}),
575
							t('files_sharing', 'Invalid ownCloud url'));
576
					} else {
577
						OC.redirect(protocol + '://' + url);
578
					}
579
				});
580
			}
581
		},
582
583
		/**
584
		 * Removes the moved element from the UI and refreshes the view
585
		 *
586
		 * @param {string} dir
587
		 * @param {string}filePath
588
		 * @param {jQuery} $item
589
		 * @private
590
		 */
591
		_removeElement: function (dir, filePath, $item) {
592
			var images = Gallery.albumMap[Gallery.currentAlbum].images;
593
			var albums = Gallery.albumMap[Gallery.currentAlbum].subAlbums;
594
			// if still viewing the same directory
595
			if (Gallery.currentAlbum === dir) {
596
				var removed = false;
597
				// We try to see if an image was removed
598
				var movedImage = _(images).findIndex({path: filePath});
599
				if (movedImage >= 0) {
600
					images.splice(movedImage, 1);
601
					removed = true;
602
				} else {
603
					// It wasn't an image, so try to remove an album
604
					var movedAlbum = _(albums).findIndex({path: filePath});
605
					if (movedAlbum >= 0) {
606
						albums.splice(movedAlbum, 1);
607
						removed = true;
608
					}
609
				}
610
611
				if (removed) {
612
					$item.remove();
613
					// Refresh the photowall without checking if new files have arrived in the
614
					// current album
615
					// TODO On the next visit this album is going to be reloaded, unless we can get
616
					// an etag back from the move endpoint
617
					Gallery.view.init(Gallery.currentAlbum);
618
				}
619
			}
620
		}
621
	};
622
	window.Gallery = Gallery;
623
})(jQuery, OC, t);
624